/*
	Copyright (c) 2004-2009, The Dojo Foundation All Rights Reserved.
	Available via Academic Free License >= 2.1 OR the modified BSD license.
	see: http://dojotoolkit.org/license for details
*/

/*
	This is a compiled version of Dojo, built for deployment and not for
	development. To get an editable version, please visit:

		http://dojotoolkit.org

	for documentation and information on getting the source.
*/

if(!dojo._hasResource["dojox.embed.Flash"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.embed.Flash"] = true;
dojo.provide("dojox.embed.Flash");

(function(){
	/*******************************************************
		dojox.embed.Flash

		Base functionality to insert a flash movie into
		a document on the fly.

		Usage:
		var movie=new dojox.embed.Flash({ args }, containerNode);
	 ******************************************************/
	var fMarkup, fVersion;
	var minimumVersion = 9; // anything below this will throw an error (may overwrite)
	var keyBase = "dojox-embed-flash-", keyCount=0;
	var _baseKwArgs = {
		expressInstall: false,
		width: 320,
		height: 240,
		swLiveConnect: "true",
		allowScriptAccess: "sameDomain",
		allowNetworking:"all",
		style: null,
		redirect: null
	};

	function prep(kwArgs){
		// console.warn("KWARGS:", kwArgs)
		kwArgs = dojo.delegate(_baseKwArgs, kwArgs);

		if(!("path" in kwArgs)){
			console.error("dojox.embed.Flash(ctor):: no path reference to a Flash movie was provided.");
			return null;
		}

		if(!("id" in kwArgs)){
			kwArgs.id = (keyBase + keyCount++);
		}
		return kwArgs;
	}

	if(dojo.isIE){
		fMarkup = function(kwArgs){
			kwArgs = prep(kwArgs);
			if(!kwArgs){ return null; }
			
			var p;
			var path = kwArgs.path;
			if(kwArgs.vars){
				var a = [];
				for(p in kwArgs.vars){
					a.push(p + '=' + kwArgs.vars[p]);
				}
				path += ((path.indexOf("?") == -1) ? "?" : "&") + a.join("&");
			}
			// FIXME: really? +'s?
			var s = '<object id="' + kwArgs.id + '" '
				+ 'classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" '
				+ 'width="' + kwArgs.width + '" '
				+ 'height="' + kwArgs.height + '"'
				+ ((kwArgs.style)?' style="' + kwArgs.style + '"':'')
				+ '>'
				+ '<param name="movie" value="' + path + '" />';
			if(kwArgs.params){
				for(p in kwArgs.params){
					s += '<param name="' + p + '" value="' + kwArgs.params[p] + '" />';
				}
			}
			s += '</object>';
			return { id: kwArgs.id, markup: s };
		};

		fVersion = (function(){
			var testVersion = 10, testObj = null;
			while(!testObj && testVersion > 7){
				try {
					testObj = new ActiveXObject("ShockwaveFlash.ShockwaveFlash." + testVersion--);
				}catch(e){ }
			}
			if(testObj){
				var v = testObj.GetVariable("$version").split(" ")[1].split(",");
				return {
					major: (v[0]!=null) ? parseInt(v[0]) : 0, 
					minor: (v[1]!=null) ? parseInt(v[1]) : 0, 
					rev: (v[2]!=null) ? parseInt(v[2]) : 0 
				};
			}
			return { major: 0, minor: 0, rev: 0 };
		})();

		//	attach some cleanup for IE, thanks to deconcept :)
		dojo.addOnUnload(function(){
			var dummy = function(){};
			var objs = dojo.query("object").
				reverse().
				style("display", "none").
				forEach(function(i){
					for(var p in i){
						if((p != "FlashVars") && dojo.isFunction(i[p])){
							try{
								i[p] = dummy;
							}catch(e){}
						}
					}
				});
		});

		//	TODO: ...and double check this fix; is IE really firing onbeforeunload with any kind of href="#" link?
		/*
		var beforeUnloadHandle = dojo.connect(dojo.global, "onbeforeunload", function(){
			try{
				if(__flash_unloadHandler){ __flash_unloadHandler=function(){ }; }
				if(__flash_savedUnloadHandler){ __flash_savedUnloadHandler=function(){ }; }
			} catch(e){ }
			dojo.disconnect(beforeUnloadHandle);
		});
		*/
	} else {
		//	*** Sane browsers branch ******************************************************************
		fMarkup = function(kwArgs){
			kwArgs = prep(kwArgs);
			if(!kwArgs){ return null; }
			
			var p;
			var path = kwArgs.path;
			if(kwArgs.vars){
				var a = [];
				for(p in kwArgs.vars){
					a.push(p + '=' + kwArgs.vars[p]);
				}
				path += ((path.indexOf("?") == -1) ? "?" : "&") + a.join("&");
			}
			var s = '<embed type="application/x-shockwave-flash" '
				+ 'src="' + path + '" '
				+ 'id="' + kwArgs.id + '" '
				//+ 'name="' + kwArgs.id + '" '
				+ 'width="' + kwArgs.width + '" '
				+ 'height="' + kwArgs.height + '"'
				+ ((kwArgs.style)?' style="' + kwArgs.style + '" ':'')
				+ 'swLiveConnect="'+kwArgs.swLiveConnect+'" '
				+ 'allowScriptAccess="' +kwArgs.allowScriptAccess+  '" '
				+ 'allowNetworking="' +kwArgs.allowNetworking+  '" '
				
				+ 'pluginspage="' + window.location.protocol + '//www.adobe.com/go/getflashplayer" ';
			if(kwArgs.params){
				for(p in kwArgs.params){
					s += ' ' + p + '="' + kwArgs.params[p] + '"';
				}
			}
			s += ' />';
			return { id: kwArgs.id, markup: s };
		};

		fVersion=(function(){
			var plugin = navigator.plugins["Shockwave Flash"];
			if(plugin && plugin.description){
				var v = plugin.description.replace(/([a-zA-Z]|\s)+/, "").replace(/(\s+r|\s+b[0-9]+)/, ".").split(".");
				return { 
					major: (v[0]!=null) ? parseInt(v[0]) : 0, 
					minor: (v[1]!=null) ? parseInt(v[1]) : 0, 
					rev: (v[2]!=null) ? parseInt(v[2]) : 0 
				};
			}
			return { major: 0, minor: 0, rev: 0 };
		})();
	}


	/*=====
	dojox.embed.__flashArgs = function(path, id, width, height, style, params, vars, expressInstall, redirect){
		//	path: String
		//		The URL of the movie to embed.
		//	id: String?
		//		A unique key that will be used as the id of the created markup.  If you don't
		//		provide this, a unique key will be generated.
		//	width: Number?
		//		The width of the embedded movie; the default value is 320px.
		//	height: Number?
		//		The height of the embedded movie; the default value is 240px
		//	minimumVersion: Number ?
		//		The minimum targeted version of the Flash Player (defaults to 9) 
		//	style: String?
		//		Any CSS style information (i.e. style="background-color:transparent") you want
		//		to define on the markup.
		//	params: Object?
		//		A set of key/value pairs that you want to define in the resultant markup.
		//	vars: Object?
		//		A set of key/value pairs that the Flash movie will interpret as FlashVars.
		//	expressInstall: Boolean?
		//		Whether or not to include any kind of expressInstall info. Default is false.
		//	redirect: String?
		//		A url to redirect the browser to if the current Flash version is not supported.
		this.id=id;
		this.path=path;
		this.width=width;
		this.minimumVersion=minimumVersion;
		this.height=height;
		this.style=style;
		this.params=params;
		this.vars=vars;
		this.expressInstall=expressInstall;
		this.redirect=redirect;
	}
	=====*/

	//	the main entry point
	dojox.embed.Flash = function(/*dojox.embed.__flashArgs*/ kwArgs, /*DOMNode*/ node){
		//	summary:
		//		Creates a wrapper object around a Flash movie.  Wrapper object will
		//		insert the movie reference in node; when the browser first starts
		//		grabbing the movie, onReady will be fired; when the movie has finished
		//		loading, it will fire onLoad.
		//
		//		If your movie uses ExternalInterface, you should use the onLoad event
		//		to do any kind of proxy setup (see dojox.embed.Flash.proxy); this seems
		//		to be the only consistent time calling EI methods are stable (since the
		//		Flash movie will shoot several methods into the window object before
		//		EI callbacks can be used properly).
		//
		//	arguments:
		//		kwArgs: dojox.embed.__flashArgs
		//			See dojox.embed.__flashArgs
		//
		//		node:	DomNode
		//			The node where the embed object will be placed
		//
		// 	properties:
		//		id: String
		//			The ID of the internal embed/object tag.  Can be used to get a reference to
		//			the movie itself.
		//		movie: HTMLObject
		//			A reference to the Flash movie itself.
		//
		//	example:
		//		Embed a flash movie in a document using the new operator, and get a reference to it.
		//	|	var movie = new dojox.embed.Flash({
		//	|		path: "path/to/my/movie.swf",
		//	|		width: 400,
		//	|		height: 300
		//	|	}, myWrapperNode, "testLoaded");
		//
		//	example:
		//		Embed a flash movie in a document without using the new operator.
		//	|	var movie = dojox.embed.Flash({
		//	|		path: "path/to/my/movie.swf",
		//	|		width: 400,
		//	|		height: 300,
		//	|		style: "position:absolute;top:0;left:0"
		//	|	}, myWrapperNode, "testLoaded");
		//
		// File can only be run from a server, due to SWF dependency.
		if(location.href.toLowerCase().indexOf("file://")>-1){
			throw new Error("dojox.embed.Flash can't be run directly from a file. To instatiate the required SWF correctly it must be run from a server, like localHost.");
		}
		this.available = dojox.embed.Flash.available;
		this.minimumVersion = kwArgs.minimumVersion || minimumVersion;
		//console.log("AVAILABLE:", this);
		this.id = null;
		this.movie = null;
		this.domNode = null;
		if(node){
			node = dojo.byId(node);
		}
		// setTimeout Fixes #8743 - creating double SWFs
		// also allows time for code to attach to onError
		setTimeout(dojo.hitch(this, function(){
			if(this.available && this.available >= this.minimumVersion){
				if(kwArgs && node){
					this.init(kwArgs, node);
				}// FIXME: else what?
				
			}else{
				if(!this.available){
					this.onError("Flash is not installed.");
				}else{
					this.onError("Flash version detected: "+this.available+" is out of date. Minimum required: "+this.minimumVersion);
				}
			}
		}), 100);
	};

	dojo.extend(dojox.embed.Flash, {
		onReady: function(/*HTMLObject*/ movie){
			//	summary:
			//		Stub function for you to attach to when the movie reference is first
			//		pushed into the document.
		},
		onLoad: function(/*HTMLObject*/ movie){
			//	summary:
			//		Stub function for you to attach to when the movie has finished downloading
			//		and is ready to be manipulated.
		},
		onError: function(msg){
			
		},
		_onload: function(){
			// summary:
			//	Internal. Cleans up before calling onLoad. 
			clearInterval(this._poller);
			delete this._poller;
			delete this._pollCount;
			delete this._pollMax;
			this.onLoad(this.movie);
		},
		init: function(/*dojox.embed.__flashArgs*/ kwArgs, /*DOMNode?*/ node){
			//	summary
			//		Initialize (i.e. place and load) the movie based on kwArgs.
			this.destroy();		//	ensure we are clean first.
			node = dojo.byId(node || this.domNode);
			if(!node){ throw new Error("dojox.embed.Flash: no domNode reference has been passed."); }
			
			// vars to help determine load status
			var p = 0, testLoaded=false;
			this._poller = null; this._pollCount = 0; this._pollMax = 5; this.pollTime = 100;
			
			if(dojox.embed.Flash.initialized){
				
				this.id = dojox.embed.Flash.place(kwArgs, node);
				this.domNode = node;

				setTimeout(dojo.hitch(this, function(){
					this.movie = this.byId(this.id, kwArgs.doc);
					this.onReady(this.movie);
					
					this._poller = setInterval(dojo.hitch(this, function(){
						
						// catch errors if not quite ready.
						try{
							p = this.movie.PercentLoaded();
						}catch(e){
							/* squelch */
							console.warn("this.movie.PercentLoaded() failed");
						};
						
						if(p == 100){
							// if percent = 100, movie is fully loaded and we're communicating
							this._onload();
						
						}else if(p==0 && this._pollCount++ > this._pollMax){
							// after several attempts, we're not past zero.
							// FIXME: What if we get stuck on 33% or something?
							clearInterval(this._poller);
							throw new Error("Building SWF failed.");
						}
					}), this.pollTime);
				}), 1);
			}
		},
		_destroy: function(){
			//	summary
			//		Kill the movie and reset all the properties of this object.
			try{
				this.domNode.removeChild(this.movie);
			}catch(e){}
			this.id = this.movie = this.domNode = null;
		},
		destroy: function(){
			//	summary
			//		Public interface for destroying all the properties in this object.
			//		Will also clean all proxied methods.
			if(!this.movie){ return; }
			
			//	remove any proxy functions
			var test = dojo.delegate({ 
				id: true,
				movie: true,
				domNode: true,
				onReady: true,
				onLoad: true 
			});
			for(var p in this){
				if(!test[p]){
					delete this[p];
				}
			}

			//	pull the movie
			if(this._poller){
				//	wait until onLoad to destroy
				dojo.connect(this, "onLoad", this, "_destroy");
			} else {
				this._destroy();
			}
		},
		byId: function (movieName, doc){
			// 	summary:
			//		Gets Flash movie by id.
			//	description:
			//		Probably includes methods for outdated
			//		browsers, but this should catch all cases.
			// arguments:
			//		movieName: String
			//			The name of the SWF
			//		doc: Object
			//			The document, if not current window
			//			(not fully supported)
			//	example:
			//	| var movie = dojox.embed.Flash.byId("myId");
			//
			doc = doc || document;
			if(doc.embeds[movieName]){
				return doc.embeds[movieName];
			}
			if(doc[movieName]){
				return doc[movieName];
			}
			if(window[movieName]){
				return window[movieName];
			}
			if(document[movieName]){
				return document[movieName];
			}
			return null;
		}
	});
	
	//	expose information through the constructor function itself.
	dojo.mixin(dojox.embed.Flash, {
		//	summary:
		//		A singleton object used internally to get information
		//		about the Flash player available in a browser, and
		//		as the factory for generating and placing markup in a
		//		document.
		//
		//	minSupported: Number
		//		The minimum supported version of the Flash Player, defaults to 8.
		//	available: Number
		//		Used as both a detection (i.e. if(dojox.embed.Flash.available){ })
		//		and as a variable holding the major version of the player installed.
		//	supported: Boolean
		//		Whether or not the Flash Player installed is supported by dojox.embed.
		//	version: Object
		//		The version of the installed Flash Player; takes the form of
		//		{ major, minor, rev }.  To get the major version, you'd do this:
		//		var v=dojox.embed.Flash.version.major;
		//	initialized: Boolean
		//		Whether or not the Flash engine is available for use.
		//	onInitialize: Function
		//		A stub you can connect to if you are looking to fire code when the 
		//		engine becomes available.  A note: DO NOT use this event to
		//		place a movie in a document; it will usually fire before DOMContentLoaded
		//		is fired, and you will get an error.  Use dojo.addOnLoad instead.
		minSupported : 8,
		available: fVersion.major,
		supported: (fVersion.major >= fVersion.required),
		minimumRequired: fVersion.required,
		version: fVersion,
		initialized: false,
		onInitialize: function(){
			dojox.embed.Flash.initialized = true;
		},
		__ie_markup__: function(kwArgs){
			return fMarkup(kwArgs);
		},
		proxy: function(/*dojox.embed.Flash*/ obj, /*Array|String*/ methods){
			//	summary:
			//		Create the set of passed methods on the dojox.embed.Flash object
			//		so that you can call that object directly, as opposed to having to
			//		delve into the internal movie to do this.  Intended to make working
			//		with Flash movies that use ExternalInterface much easier to use.
			//
			//	example:
			//		Create "setMessage" and "getMessage" methods on foo.
			//	|	var foo = new dojox.embed.Flash(args, someNode);
			//	|	dojo.connect(foo, "onLoad", dojo.hitch(foo, function(){
			//	|		dojox.embed.Flash.proxy(this, [ "setMessage", "getMessage" ]);
			//	|		this.setMessage("dojox.embed.Flash.proxy is pretty cool...");
			//	|		console.log(this.getMessage());
			//	|	}));
			dojo.forEach((dojo.isArray(methods) ? methods : [ methods ]), function(item){
				this[item] = dojo.hitch(this, function(){
					return (function(){
						return eval(this.movie.CallFunction(
							'<invoke name="' + item + '" returntype="javascript">'
							+ '<arguments>'
							+ dojo.map(arguments, function(item){
								// FIXME: 
								//		investigate if __flash__toXML will
								//		accept direct application via map()
								//		(e.g., does it ignore args past the
								//		first? or does it blow up?)
								return __flash__toXML(item);
							}).join("")
							+ '</arguments>'
							+ '</invoke>'
						));
					}).apply(this, arguments||[]);
				});
			}, obj);
		}
	});

	if(dojo.isIE){
		//	Ugh!
		if(dojo._initFired){
			var e = document.createElement("script");
			e.type = "text/javascript";
			e.src = dojo.moduleUrl("dojox", "embed/IE/flash.js");
			document.getElementsByTagName("head")[0].appendChild(e);
		}else{
			//	we can use document.write.  What a kludge.
			document.write('<scr'+'ipt type="text/javascript" src="' + dojo.moduleUrl("dojox", "embed/IE/flash.js") + '">'
				+ '</scr'+'ipt>');
		}
	}else{
		dojox.embed.Flash.place = function(kwArgs, node){
			var o = fMarkup(kwArgs);
			node = dojo.byId(node);
			if(!node){ 
				node = dojo.doc.createElement("div");
				node.id = o.id+"-container";
				dojo.body().appendChild(node);
			}
			if(o){
				node.innerHTML = o.markup;
				return o.id;
			}
			return null;
		}
		dojox.embed.Flash.onInitialize();
	}
})();

}

if(!dojo._hasResource["dojox.html.styles"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.html.styles"] = true;
dojo.provide("dojox.html.styles");
	
	// summary:
	//		Methods for creating and minipulating dynamic CSS Styles and Style Sheets
	//
	// example:
	//		| dojox.html.createStyle("#myDiv input", "font-size:24px");
	//			Creates Style #myDiv input, which can now be applied to myDiv, and 
	//			the inner input will be targeted
	//		| dojox.html.createStyle(".myStyle", "color:#FF0000");
	//			Now the class myStyle can be assigned to a node's className
	
(function(){
	
	var dynamicStyleMap = {};
	var pageStyleSheets = {};
	var titledSheets = [];
	var styleIndicies = [];
	
	dojox.html.insertCssRule = function(/*String*/selector, /*String*/declaration, /*String*/styleSheetName){
		// summary:
		//	Creates a style and attaches it to a dynamically created stylesheet
		//	arguments:
		//		selector: 	
		//					A fully qualified class name, as it would appear in
		//					a CSS dojo.doc. Start classes with periods, target
		//					nodes with '#'. Large selectors can also be created
		//					like:
		//					| "#myDiv.myClass span input"
		//		declaration:
		//					A single string that would make up a style block, not
		//					including the curly braces. Include semi-colons between
		//					statements. Do not use JavaScript style declarations
		//					in camel case, use as you would in a CSS dojo.doc:
		//					| "color:#ffoooo;font-size:12px;margin-left:5px;"
		//		styleSheetName: ( optional )
		//					Name of the dynamic style sheet this rule should be 
		//					inserted into. If is not found by that name, it is
		//					created. If no name is passed, the name "default" is 
		//					used.
		//
		var ss = dojox.html.getDynamicStyleSheet(styleSheetName);
		var styleText = selector + " {" + declaration + "}";
		console.log("insertRule:", styleText)
		if(dojo.isIE){
			// Note: check for if(ss.cssText) does not work
			ss.cssText+=styleText;
			console.log("ss.cssText:", ss.cssText)
		}else if(ss.sheet){
			ss.sheet.insertRule(styleText, ss._indicies.length);
		}else{
			ss.appendChild(dojo.doc.createTextNode(styleText));
		}
		ss._indicies.push(selector+" "+declaration);
		return selector; // String 
	
	}
	
	dojox.html.removeCssRule = function(/*String*/selector, /*String*/declaration, /*String*/styleSheetName){
		// summary:
		//		Removes a cssRule base on the selector and declaration passed
		//		The declaration is needed for cases of dupe selectors
		// description: Only removes DYNAMICALLY created cssRules. If you 
		//		created it with dojox.html.insertCssRule, it can be removed.
		//
		var ss;
		var index=-1;
		for(var nm in dynamicStyleMap){
			if(styleSheetName && styleSheetName!=nm) {continue;}
			ss = dynamicStyleMap[nm];
			for(var i=0;i<ss._indicies.length;i++){
				if(selector+" "+declaration == ss._indicies[i]){
					index = i;
					break;
				}
			}
			if(index>-1) { break; }
		}
		if(!ss){
			console.log("No dynamic style sheet has been created from which to remove a rule.");
			return false;
		}
		if(index==-1){
			console.log("The css rule was not found and could not be removed.");
			return false;
		}
		
		ss._indicies.splice(index, 1);
		
		
		
		if(dojo.isIE){ 
			// Note: check for if(ss.removeRule) does not work
			ss.removeRule(index);
		}else if(ss.sheet){
			ss.sheet.deleteRule(index);
		}else if(document.styleSheets[0]){
			console.log("what browser hath useth thith?")
			//
		}
		return true; //Boolean
		
	}
	
	/* TODO
	dojox.html.modifyCssRule = function(selector, declaration, styleSheetName){
		Not implemented - it seems to have some merit for changing some complex 
		selectors. It's not much use for changing simple ones like "span".
		For now, simply write a new rule which will cascade over the first.
		// summary
		//	Modfies an existing cssRule
	}
	*/
	
	dojox.html.getStyleSheet = function(/*String*/styleSheetName){
		// summary:
		//		Returns a style sheet based on the argument.
		//		Searches dynamic style sheets first. If no matches,
		//		searches document style sheets.
		//
		// argument: (optional)
		//		A title or an href to a style sheet. Title can be 
		//		an attribute in a tag, or a dynamic style sheet 
		//		reference. Href can be the name of the file.
		//		If no argument, the assumed created dynamic style 
		//		sheet is used.
		
		// try dynamic sheets first 
		if(dynamicStyleMap[styleSheetName || "default"]){
			return dynamicStyleMap[styleSheetName || "default"];
		}
		if(!styleSheetName){
			// no arg is nly good for the default style sheet 
			// and it has not been created yet.
			return false;
		}
		
		var allSheets = dojox.html.getStyleSheets();
		
		// now try document style sheets by name
		if(allSheets[styleSheetName]){
			return dojox.html.getStyleSheets()[styleSheetName];
		}
		
		// check for partial matches in hrefs (so that a fully 
		//qualified name does not have to be passed)
		for ( var nm in allSheets){
			if(	allSheets[nm].href && allSheets[nm].href.indexOf(styleSheetName)>-1){
				return allSheets[nm];
			}
		}
		return false; //StyleSheet or false
	}
	
	dojox.html.getDynamicStyleSheet = function(/*String*/styleSheetName){
		// summary:
		//		Creates and returns a dynamically created style sheet
		// 		used for dynamic styles
		//
		//	argument:
		//			styleSheetName /* optional String */
		//			The name given the style sheet so that multiple 
		//			style sheets can be created and referenced. If 
		//			no argument is given, the name "default" is used.
		//
		if(!styleSheetName){ styleSheetName="default"; }
		
		if(!dynamicStyleMap[styleSheetName]){
			if(dojo.doc.createStyleSheet){ //IE
			
				dynamicStyleMap[styleSheetName] = dojo.doc.createStyleSheet();
				dynamicStyleMap[styleSheetName].title = styleSheetName;

			}else{
				dynamicStyleMap[styleSheetName] = dojo.doc.createElement("style");
				dynamicStyleMap[styleSheetName].setAttribute("type", "text/css");
				dojo.doc.getElementsByTagName("head")[0].appendChild(dynamicStyleMap[styleSheetName]);
				console.log(styleSheetName, " ss created: ", dynamicStyleMap[styleSheetName].sheet);
			}
			dynamicStyleMap[styleSheetName]._indicies = [];
		}
		
		
		return dynamicStyleMap[styleSheetName]; //StyleSheet
	}

	dojox.html.enableStyleSheet = function(/*String*/styleSheetName){
		// summary:
		//		Enables the style sheet with the name passed in the
		//		argument. Deafults to the default style sheet.
		//
		var ss = dojox.html.getStyleSheet(styleSheetName);
		if(ss){ 
			if(ss.sheet){
				ss.sheet.disabled = false; 
			}else{
				ss.disabled = false; 
			}
		}
	}

	dojox.html.disableStyleSheet = function(styleSheetName){
		// summary:
		//		Disables the dynamic style sheet with the name passed in the
		//		argument. If no arg is passed, defaults to the default style sheet.
		//
		var ss = dojox.html.getStyleSheet(styleSheetName);
		if(ss){ 
			if(ss.sheet){
				ss.sheet.disabled = true; 
			}else{
				ss.disabled = true; 
			}
		}
	}
	
	dojox.html.activeStyleSheet = function(/*?String*/title){
		// summary:
		//		Getter/Setter
		// description:
		//		If passed a title, enables a that style sheet. All other
		//		toggle-able style sheets are disabled.
		//		If no argument is passed, returns currently enabled
		//		style sheet.
		//
		var sheets = dojox.html.getToggledStyleSheets();
		if(arguments.length == 1){
			//console.log("sheets:", sheets);
			dojo.forEach(sheets, function(s){
				s.disabled = (s.title == title) ? false : true;
				//console.log("SWITCHED:", s.title, s.disabled, s.id);
			});
		}else{
			for(var i=0; i<sheets.length;i++){
				if(sheets[i].disabled == false){
					return sheets[i];
				}
			}
		}
		return true; //StyleSheet or Boolean - FIXME - doesn't make a lot of sense
	}
	
	dojox.html.getPreferredStyleSheet = function(){
		// summary
		//	Returns the style sheet that was initially enabled
		//	on document launch.
		
		//TODO
	}
	
	
	
	
	dojox.html.getToggledStyleSheets = function(){
		// summary:
		//		Searches HTML for style sheets that are "toggle-able" - 
		//		can be enabled and disabled. These would include sheets
		//		with the title attribute, as well as the REL attribute.
		//	returns:
		//		An array of all toggle-able style sheets
		//	TODO: 	Sets of style sheets could be grouped according to
		//			an ID and used in sets, much like different
		//			groups of radio buttons. It would not however be
		//			according to W3C spec
		//
		if(!titledSheets.length){
			var sObjects = dojox.html.getStyleSheets();
			for(var nm in sObjects){
				
				if(sObjects[nm].title){
					//console.log("TITLE:", sObjects[nm].title, sObjects[nm])
					titledSheets.push(sObjects[nm]);
				}
			}
		}
		return titledSheets; //Array
	}
	
	
	dojox.html.getStyleSheets = function(){
		// summary:
		//		Collects all the style sheets referenced in the HTML page,
		//		including any incuded via @import. 
		//
		//	returns: 
		//		An hash map of all the style sheets.
		//
		//	TODO: 	Does not recursively search for @imports, so it will
		//			only go one level deep.
		//
		if(pageStyleSheets.collected) {return pageStyleSheets;}
		
		var sheets = dojo.doc.styleSheets;
		//console.log("styleSheets:", sheets);
		dojo.forEach(sheets, function(n){
			var s = (n.sheet) ? n.sheet : n;
			var name = s.title || s.href;
			if(dojo.isIE){
				// IE attaches a style sheet for VML - do not include this
				if(s.cssText.indexOf("#default#VML")==-1){
					
					
					if(s.href){
						// linked		
						pageStyleSheets[name] = s;
					
					}else if(s.imports.length){
						// Imported via @import
						dojo.forEach(s.imports, function(si){
							pageStyleSheets[si.title || si.href] = si;
						});
						
					}else{
						//embedded within page
						pageStyleSheets[name] = s;
					}
				}
				
			}else{
				//linked or embedded
				pageStyleSheets[name] = s;
				pageStyleSheets[name].id = s.ownerNode.id;
				dojo.forEach(s.cssRules, function(r){
					if(r.href){
						// imported
						pageStyleSheets[r.href] = r.styleSheet;
						pageStyleSheets[r.href].id = s.ownerNode.id;
					}
				});
			
			}
			
		});
		
		//console.log("pageStyleSheets:", pageStyleSheets);
		
		
		pageStyleSheets.collected = true;
		return pageStyleSheets; //Object
	}
	

})();

}

if(!dojo._hasResource["dojox.form.FileUploader"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.form.FileUploader"] = true;
dojo.provide("dojox.form.FileUploader");
dojo.experimental("dojox.form.FileUploader");
var swfPath = dojo.config.uploaderPath || dojo.moduleUrl("dojox.form", "resources/uploader.swf");





dojo.declare("dojox.form.FileUploader", null, {
	// summary: 
	// 		Handles File Uploading to a server (PHP script included for testing)
	//		Does *NOT* create a button, it transforms a button into an uploader. 
	//		This can be used for toolbar buttons for example.
	//
	// description:
	//		If the correct version of Flash Player is available (> 9.0) , a SWF
	//		is used. If Flash Player is not installed or is outdated, a typical
	//		html fileInput is used. This process can be overridden with
	//		force:"flash" or force:"html".
	//
	//		FileUploader now works with Flash 10, but it comes with consequences.
	//		Instead of calling to open the browse dialog with script, we HAVE to
	//		click a Flash button. Therefore, we are floating a SWF over the 'fake'
	//		button just like we do with the fileInput. As a result, the Flash 
	//		uploader will have the same CSS problems as the fileInput.
	//
	//	NEW FEATURES - 
	//		You can now pass in POST data that will be posted to the server along
	//		with the Flash uploaded files. Also, you can now specify the field name
	//		that the server expects the files to be in.
	//
	//	CDN USERS - 
	//		FileUpload now works with the CDN but with limitations. The SWF must 
	//		be from the same domain as the HTML page. 'swfPath' has been exposed
	//		so that you may link to that file (could of course be the same SWF in 
	//		dojox resource folder). The SWF will *NOT* work from the
	//		CDN server. This would require a special XML file that would allow 
	//		access to your server, and the logistics to that is impossible.
	//		
	// LIMITATIONS -
	//		Because of the nature of this "hack" - floating a zero-opacity fileInput
	//		over a "fake" button - this won't work in all circumstances. For instance
	//		you couldn't put a fileInput in a scrolling div. Some complicated CSS can 
	//		mess up the placement - or for that matter, some simple, but not expected
	//		CSS can mess up the placement. Being near the botton of a complex document
	//		can throw off the positioning. The positioning methods have been exposed
	//		for over-writing in these cases.
	//
	//	OPERA USERS -
	//		Not much love from Opera on FileInput hacks. Should still work with 
	//		the Flash 10 hack though.
	//
	//	ALSO - 
	//		Only works programmatically. Does not work in markup. Use the other
	//		other FileInput files for markup solutions.
	//
	//	example:
	//		|	var f1 = new dojox.form.FileUploader({
	//		|		id:"upload_1",
	//		|		devMode:false,
	//		|		isDebug:false,
	//		|		button:dijit.byId("btn1"), 
	//		|		uploadUrl:"www.absolutelUrl.com/upload.php", 
	//		|		uploadOnChange:true
	//		|	});
	//		|	dojo.connect(f1, "onChange", "handleChange");
	//		|	dojo.connect(f1, "onComplete", "onComplete");
	//
	// arguments:
	//
	// degradable: REMOVED
	//
	//	isDebug: Boolean
	//		If true, outputs traces from the SWF to console. What exactly gets passed
	//		is very relative, and depends upon what traces have been left in the DEFT SWF.
	isDebug:false,
	//
	//	devMode: Boolean.
	//		If true, gives a red overlay to the Flash button and the HTML fileInput button's
	//		opcaity is set to 1.0. Since this code uses some crazy CSS to get the uploaders 
	//		to hover over the 'fake' button, there is no garuantee that it will work in all 
	//		cases. Set this param to true to see if the button is properly positioned.
	//		Methods may be called over over-written to help in this case.
	devMode:false,
	//
	//	id: String
	//		The object id, just like any other widget in Dojo. However, this id
	//		is also used as a reference for the SWF
	id:"",
	//
	//	uploadUrl: String
	// 		REQUIRED: The Url to where the file will be uploaded
	uploadUrl: "",
	//
	//	button: dijit.form.Button or a domNode
	// 		REQUIRED: The button that when clicked, launches the upload dialog
	button: null,
	//
	//	uploadOnChange: Boolean
	//		If true, uploads imeediately after a file has been selected. If false,
	//		waits for upload() to be called.
	uploadOnChange: false,
	//	selectMultipleFiles: Boolean
	//		If true and flash mode, multiple files may be selected from the dialog.
	//		If html mode, files are not uploaded until upload() is called. The references
	//		to each file is incremented:uploadedfile0, uploadedfile1, uploadedfile2... etc.
	selectMultipleFiles: true,
	//
	//	htmlFieldName: String
	//		The name of the field of the fileInput that the server is expecting
	htmlFieldName:"uploadedfile",
	//
	//	flashFieldName: String
	//		The name of the field of the flash uploaded files that the server is expecting
	flashFieldName:"flashUploadFiles",
	// fileMask:  Array[ Array[Description, FileTypes], Array[...]...] 
	// 		(an array, or an array of arrays)
	//		Restrict file selection to certain file types
	// 		Empty array defaults to "All Files"
	// example:
	//	fileMask = ["Images", "*.jpg;*.jpeg;*.gif;*.png"]
	//	or
	//	fileMask = [
	//		["Jpeg File", 	"*.jpg;*.jpeg"],
	//		["GIF File", 	"*.gif"],
	//		["PNG File", 	"*.png"],
	//		["All Images", 	"*.jpg;*.jpeg;*.gif;*.png"],
	//	]
	//	NOTE: MacType is not supported, as it does not work very well.
	//			fileMask will work on a Mac, but differently than 
	//			Windows.
	fileMask: [],
	//
	//	force: String
	//			options:
	//				"flash" forces Flash Uploader
	//				"html" forces HTML fileInput
	//				"" checks availability of the proper Flash player
	force:"",
	//
	//	postData: Object
	//		FLASH ONLY - In HTML, append the vars to the uploadUrl
	//		Sends data via POST to the server along with the uploaded
	//		files.
	//	NEW:
	//		You can also pass postData in the upload method
	//		which can be different with each upload
	postData:null,
	//
	//	swfPath: String
	// 		optional: pass in a path to your own SWF file uploader. defaults to the one in dojox.
	//		CDN USERS NOTE: For the Flash Uploader to work via CDN, the SWF must be from the 
	//		same server as the HTML page. Pass the link to that file here.
	swfPath: swfPath,
	//
	//	minFlashVersion: Number
	//		Internal. Version of Flash Player to check for. Thi may be over-written
	//		for testing.
	minFlashVersion: 9,
	//
	//	uploaderType: String
	//		Internal.
	uploaderType:"",
	//
	//	flashObject: dojox.embed.Flash 
	//		The object that creates the SWF embed object. Mostly Internal.
	flashObject: null,
	//
	//	flashMovie: Function
	//		The SWF. Mostly Internal.
	flashMovie: null,
	//
	//	flashDiv: HTMLNode
	//		The div that holds the SWF. While mostly internal, ccould be accessed 
	//		for advanced positioning.
	flashDiv: null,
	//
	//	domNode: HTMLNode
	//either flash div or fileInput, depending on type
	domNode:null, 
	
	constructor: function(options){
		// summary:
		//		Calling init function instead of doing operations in 
		//		constructor, to allow for patches and over-writes.
		//
		this.init(options);
	},
	
	log: function(){
		//	summary:
		//		Due to the excessive logging necessary to make this code happen,
		//		It's easier to turn it on and off here in one place.
		//		Also helpful if there are multiple uploaders on one page.
		if (this.isDebug) {
			console.log.apply(console, arguments);
		}
	},
	
	init: function(options){
		//	summary:
		//		Determine which uploader to use and initialize it.
		//
		dojo.mixin(this, options);
		//this.isDebug = true;
		console.info("isdebug:", this.isDebug, options.isDebug, this.id)
		this.id = this.id || dijit.getUniqueId("uploader");
		dijit.registry.add(this);
		this.log("init Flash:", (dojox.embed.Flash.available >= this.minFlashVersion || this.force=="flash"), dojox.embed.Flash.available >= this.minFlashVersion, this.force=="flash")
		
		this.fileList = [];
		this._subs = [];
		this._cons = [];
		
		if((dojox.embed.Flash.available >= this.minFlashVersion || this.force=="flash") && this.force!="html"){
			this.uploaderType = "flash";
			this.createFlashUploader();
		}else{
			this.uploaderType = "html";
			
			this.fileInputs = [];
			this.fileCount = 0;
			
			if (dojo.isIE && dojo.isIE<7) {
				// if we are create more than one FileInputOverlay,
				// IE6 needs a breather or it locks up
				setTimeout(dojo.hitch(this, "createHtmlUploader"), 1);
			}
			else {
				this.createHtmlUploader();
			}
		}
	},
	
	onMouseDown: function(evt){
		// summary:
		//		Fired when upload button is down
		//		Stub to which user can connect
	},
	
	onMouseUp: function(evt){
		// summary:
		//		Fired when upload button is up
		//		Stub to which user can connect
	},
	
	onMouseOver: function(evt){
		// summary:
		//		Fired when upload button is over
		// 		Can be connected to for manipulating hover state
		if (this.button.domNode) {
			dojo.addClass(this.button.domNode, "dijitButtonHover dijitHover");
		}
	},
	
	onMouseOut: function(evt){
		// summary:
		//		Fired when upload button is off
		// Can be connected to for manipulating hover state
		if (this.button.domNode) {
			dojo.removeClass(this.button.domNode, "dijitButtonHover dijitHover");
		}
	},
	/*onClick: function(){
		// summary:
		//		Fired when upload button is up
		//		Stub to which user can connect
	},*/
	
	onChange: function(dataArray){
		//	summary:
		// 		stub to connect 
		// 		Fires when files are selected
		// 		Event is an array of last files selected
	},
	
	onProgress: function(dataArray){
		// summary:
		// 		Stub to connect 
		// 		Fires as progress returns from SWF
		// 		Event is an array of all files uploading
		//		Can be connected to for HTML uploader,
		//		but will not return anything.
	},
	
	onComplete: function(dataArray){
		// summary
		// stub to connect 
		// Fires when all files have uploaded
		// Event is an array of all files
	},
	
	onCancel: function(){
		// summary:
		// 		Stub to connect 
		// 		Fires when dialog box has been closed 
		//		without a file selection
		this.log("Upload Canceled")
	},
	
	onError: function(evtObject){
		//FIXME: Unsure of a standard form for receieving errors
		var type = evtObject.type ? evtObject.type.toUpperCase() : "ERROR";
		var msg = evtObject.msg ? evtObject.msg : evtObject;
		console.warn("FLASH/ERROR/"+type , msg);
	},
	
	upload: function(/*Object ? */data){
		// summary:
		// 		When called, begins file upload
		//	data: Object
		//		postData to be sent to server
		if(data){
			this.postData = data;
		}
		this.log("upload type:", this.uploaderType, " - postData:", this.postData);
		
		if (this.uploaderType == "flash") {
			try{
				this.flashMovie.doUpload(this.postData);	
			}catch(err){
				throw new Error("Sorry, the SWF failed to initialize properly. The page will have to be refreshed. ERROR:" + err)
			}
			
		}else{
			//this.log("POST FORM")
			//this.log("FORM:", this._formNode)
			//this.log("FILE:")
			dojo.io.iframe.send({
				url: this.uploadUrl,
				form: this._formNode,
				handleAs: "json",
				handle: dojo.hitch(this, function(data, ioArgs, widgetRef){
					this._complete([data]);
					//this._complete(this.selectMultipleFiles ? data : [data]);
				})
			});
		}
	},
	
	setPosition: function(){
		//	summary:
		//		Positions the upload button over the 'fake' button.
		//		This method is called on init, and may be called 
		//		for various other reasons, for example, when the browser 
		//		window is resized. Also, this code detects if the 
		//		upload button is within a Dijit Dialog, and calls
		//		this method when the Dialog is dragged. Whenever the 
		//		DOM has been redrawn, you should call this method.
		if (this.uploaderType == "flash") {
			this.setFlashPosition();
		}else{
			this.setHtmlPosition();
		}
	},

	hide: function(){
		//	summary:
		//		Hides the upload button. This is called
		//		when within a dialog.
		dojo.style(this.domNode, "display", "none");
	},
	
	show: function(){
		//	summary:
		//		Shows the upload button. This is called
		//		when within a dialog.
		dojo.style(this.domNode, "display", "");
	},
	
	disable: function(/*Boolean*/disabled){
		// summary:
		//	This method is connected to the "fake" dijit
		//	button, and hides and shows on the disabling.
		//	If the "fake" button is a dom node, this method
		//	would need to be called directly.
		if(disabled){
			this.hide();
		}else{
			this.show();
		}
	},
	destroyAll: function(){
		//	summary:
		// 		Destroys everything including 'fake' button
		if (this.button.destroy) {
			this.button.destroy();
		}else{
			dojo.destroy(this.button);
		}
		this.destroy();
	},
	
	destroy: function(){
		//	summary:
		//		Destroys flash
		//		TODO: This doesn't look complete. HTML?
		if (this.uploaderType == "flash" && !this.flashMovie) {
			this._cons.push(dojo.connect(this, "onLoad", this, "destroy"));
			return;
		}
		dojo.forEach(this._subs, function(s){
			dojo.unsubscribe(s);
		});
		dojo.forEach(this._cons, function(c){
			dojo.disconnect(c);
		});
		
		if (this.uploaderType == "flash") {
			this.flashObject.destroy();
			dojo.destroy(this.flashDiv);
		}
	},
	
	
	
	
	createFlashUploader: function(){
		//	summary
		//		Create embedded SWF
		this.log("FLASH")
		var uurl = this.uploadUrl.toLowerCase();
		if(uurl.indexOf("http")<0 && uurl.indexOf("/")!=0){
			// Appears to be a relative path. Attempt to 
			//	convert it to absolute, so it will better 
			//target the SWF.
			//
			var loc = window.location.href.split("/");
			loc.pop();
			loc = loc.join("/")+"/";
			//this.log("Fix Relative url:", this.uploadUrl);
			this.uploadUrl = loc+this.uploadUrl;
			//this.log("SWF Fixed - Relative loc:", loc, " abs loc:", this.uploadUrl);
		}else{
			//this.log("SWF did not fix upload URL");
		}
		
		
		var dim = this.getFakeButtonSize();
		
		// the size of the embedded SWF, not it's containing DIV 
		var w = "100%";
		var h = "100%";
		var args = {
			expressInstall:true,
			path: this.swfPath.uri || this.swfPath,
			width: w,
			height: h,
				allowScriptAccess:"always",
				allowNetworking:"all",
			// only pass in simple variables - no deep objects
			vars: {
				uploadDataFieldName: this.flashFieldName,
				uploadUrl: this.uploadUrl,
				uploadOnSelect: this.uploadOnChange,
				selectMultipleFiles: this.selectMultipleFiles,
				id: this.id,
				//width:w, ///   width and height mess up the embed query string. very strange.
				//height:h,
				isDebug: this.isDebug,
				devMode:this.devMode
			},
			params: {
				wmode:"transparent"
			}
		};
		if(args.vars.isDebug && window.console && window.console.dir){
			
			window.passthrough = function(){
				console.log.apply(console, arguments);
			}
			window.passthrough("Flash trace enabled.")
		}else{
			window.passthrough = function(){}
		}
		//this.log("ARG VARS:", args.vars)
		this.flashDiv = dojo.doc.createElement("div");
		this.domNode = this.flashDiv;
		dojo.body().appendChild(this.flashDiv);
		
		this._connectFlash();
		
		// Flash 10 BUG
		// Must set the position before creating the embed object
		//	or it will get created twice - seems okay after
		this.setPosition();
		
		this.flashObject = new dojox.embed.Flash(args, this.flashDiv);
		this.flashObject.onError = function(msg){
			console.warn("Flash Error:", msg);
		}
		this.flashObject.onLoad = dojo.hitch(this, function(mov){
			this.log("ONLOAD", mov)
			this.flashMovie = mov;
			this.setFlashVars();
		});
		
		
	},
	
	setFlashVars: function(){
		
		this.flashMovie.setFileMask(this.fileMask);
		this.flashMovie.setPostData(this.postData);
		console.log("setFlashVars / postData --------> ", this.postData);
		return;
		try{	
			this.flashMovie.setFileMask(this.fileMask);
			if(this.postData){
				this.flashMovie.setPostData(this.postData);
			}
		}catch(e){
			if(this.setvarTries===undefined) this.setvarTries = 0;
			this.setvarTries++
			if(this.setvarTries<10){
				setTimeout(dojo.hitch(this, "setFlashVars"), 500);	
			}else{
				console.warn("Tried to set Flash Vars and Post data but failed.")
			}
			
		}
			
	},
	
	createHtmlUploader: function(){
		// summary:
		// 		Create the fileInput overlay
		//
		if (!this.button.id) {
			this.button.id = dijit.getUniqueId("btn");
		}
		var node;
		if (this.button.domNode) {
			//this.log(this.button.domNode);this.log(this.button.id);this.log(dojo.byId(this.button.id))
			node = dojo.byId(this.button.id).parentNode.parentNode;
			// killing this event on the dijit button - it takes over the FileInput
			node.parentNode.onmousedown = function(){}
		}else {
			node = this.button.parentNode;
		}
		
		this._buildForm(node);
		
		this._buildFileInput(node);
		
		this.setPosition();
		
		this._connectInput();
		
		
	},
	
	setFlashPosition: function(){
		//	summary:
		//		Get size and location of the 'fake' node (the button)
		//		Resize, set position of the SWF
		var dim = this.getFakeButtonSize();
		// IE mainly needs the help for the timeout.
		// but may as well do it for all then the check
		// for whether we are in a dialog 
		setTimeout(dojo.hitch(this, function(){
			dojo.style(this.flashDiv, {
				position:"absolute",
				top: dim.y + "px",
				left: dim.x + "px",
				width: dim.w + "px",
				height: dim.h + "px",
				zIndex: 2001
			});
			this.log("this.flashDiv:", this.flashDiv)
		}), 100);
	},
	
	setHtmlPosition: function(){
		// summary:
		//		Get size and location of the 'fake' node (the button)
		//		Resize, set position, and clip the 'real' button (the fileInput)	
		// 		setPosition will fire on browser resize. The button may wrap to a different position
		//		and sometimes it just shifts slightly in the html, maybe because of the scrollbar.
		//
		var fake = this.getFakeButtonSize();
		
		// could memoize this, but it at 2-5ms, doesn't seem quite worth it.
		var real = dojo.marginBox(this._fileInput);
		// Now we have an extremely large fileInput button and field.
		//	We mask the areas that extend passed the boundaries of the button.
		//	Thanks to quirksmode for this hack.
		var clip = "rect(0px " + real.w + "px " + fake.h + "px " + (real.w - fake.w) + "px)";
		this._fileInput.style.clip = clip;
		
		// absolutely position the fileInput.
		this._fileInput.style.left = (fake.x + fake.w - real.w) + "px";
		this._fileInput.style.top = fake.y + "px";
		
		//PATCH
		this._fileInput.style.zIndex = 2001;
	},
	
	_connectFlash: function(){
		// 	summary:
		//		Subscribing to published topics coming from the
		//		Flash uploader.
		// 	description:
		//		Sacrificing some readbilty for compactness. this.id
		//		will be on the beginning of the topic, so more than
		//		one uploader can be on a page and can have unique calls.
		//
		this._doSub("/filesSelected", "_change");
		this._doSub("/filesUploaded", "_complete");
		this._doSub("/filesProgress", "_progress");
		this._doSub("/filesError", "_error");
		this._doSub("/filesCanceled", "onCancel");
		
		this._doSub("/up", "onMouseUp");
		this._doSub("/down", "onMouseDown");
		this._doSub("/over", "onMouseOver");
		this._doSub("/out", "onMouseOut");
		this._connectCommon();
	},
	
	_doSub: function(subStr, funcStr){
		this._subs.push(dojo.subscribe(this.id + subStr, this, funcStr));
	},
	
	_connectInput: function(){
		this._disconnect();
		this._cons.push(dojo.connect(this._fileInput, "mouseover", this, function(evt){
			this.onMouseOver(evt);
		}));
		this._cons.push(dojo.connect(this._fileInput, "mouseout", this, function(evt){
			this.onMouseOut(evt);
			this._checkHtmlCancel("off");
		}));
		this._cons.push(dojo.connect(this._fileInput, "mousedown", this, function(evt){
			this.onMouseDown(evt);
		}));
		this._cons.push(dojo.connect(this._fileInput, "mouseup", this, function(evt){
			this.onMouseUp(evt);
			this._checkHtmlCancel("up");
		}));
		
		this._cons.push(dojo.connect(this._fileInput, "change", this, function(){
			console.log("html change")
			this._checkHtmlCancel("change");
			this._change([{
				name: this._fileInput.value,
				type: "",
				size: 0
			}]);
		}));
		this._connectCommon();
		
	},
	
	_connectCommon: function(){
		this._cons.push(dojo.connect(window, "resize", this, "setPosition"));
		// a bit of a hack...
		// if all else fails, and the stupid button still isn't
		// in position, if the fakeButton is clicked on, that
		// will move it. Would require two clicks in this case.
		if(this.button.domNode){
			this._cons.push(dojo.connect(this.button, "onClick", this, "setPosition"));	
		}else{
			this._cons.push(dojo.connect(this.button, "click", this, "setPosition"));
		}
		var dialog = this._dialogParent();
		if(dialog){
			this._cons.push(dojo.connect(dialog, "show", this, function(){
				this.show();
				this.setPosition();
			}));	
			this._cons.push(
				dojo.connect(dialog, "hide", this, "hide"),
				dojo.connect(dialog, "destroy", this, "destroy") // this one may not be needed
			);
			this._subs.push(dojo.subscribe("/dnd/move/stop",this,"setPosition"));
		}
		if(this.button.domNode){
			this._cons.push(dojo.connect(this.button, "_setDisabledAttr", this, "disable"));
		}
		// in some cases, mainly due to scrollbars, the buttons
		//	are initially misplaced
		setTimeout(dojo.hitch(this, "setPosition"), 500);
	},
	_checkHtmlCancel: function(mouseType){
		if(mouseType=="change"){
			this.dialogIsOpen = false;
		}
		if(mouseType=="up"){
			this.dialogIsOpen = true;
		}
		if(mouseType=="off"){
			this.dialogIsOpen = false;
			this.onCancel();
		}
	},
	_error: function(evt){
		this.onError(evt);
	},
		
	_change: function(dataArray){
		this.fileList = this.fileList.concat(dataArray);
		this.onChange(dataArray);
		if (this.uploadOnChange) {
			this.upload();
		}
	},
	
	_complete: function(dataArray){
		this.log("_complete", dataArray);
		for (var i = 0; i < this.fileList.length; i++) {
			this.fileList[i].percent = 100;
		}
		this._progress(this.fileList);
		this.fileList = [];
		
		this.onComplete(dataArray);
	},
	
	_progress: function(dataObject){
		this.log("_progress", dataObject);
		for (var i = 0; i < this.fileList.length; i++) {
			var f = this.fileList[i];
			if (f.name == dataObject.name) {
				f.bytesLoaded = dataObject.bytesLoaded;
				f.bytesTotal = dataObject.bytesTotal;
				f.percent = Math.ceil(f.bytesLoaded / f.bytesTotal * 100);
			}
			else {
				if (!f.percent) {
					f.bytesLoaded = 0;
					f.bytesTotal = 0;
					f.percent = 0;
				}
			}
		}
		this.onProgress(this.fileList);
		
	},
	
	_dialogParent: function(){
		var dialog;
		var node = this.button.domNode || this.button;
		for(var i=0;i<50;i++){
			if(node.tagName.toLowerCase()=="body"){
				node = null;
				break;
			}
			if(node.tagName && node.tagName.toLowerCase()=="div" && (dojo.attr(node, "widgetId") || dojo.attr(node, "widgetid"))){
				dialog = dijit.byNode(node);
				if(dialog.titleBar && dialog.titleNode){
					break;	
				}else{
					dialog = null; // keep looking
				}
				
			}
			node = node.parentNode;
		}
		//console.warn("INNA DIALOG:", i, dialog)
		return dialog;
	},
	_disconnect: function(){
		dojo.forEach(this._cons, function(c){
			dojo.disconnect(c);
		});
	},
	
	_buildFileInput: function(node){
		// summary
		//	Build the fileInput field
		//
		if (this._fileInput) {
			//this._formNode.removeChild(this._fileInput);
			this._disconnect();
			dojo.style(this._fileInput, "display", "none");
		}
		this._fileInput = document.createElement('input');
		this.domNode = this._fileInput;
		this._fileInput.setAttribute("type", "file");
		this.fileInputs.push(this._fileInput);
		// server will need to know this variable:
		var nm = this.htmlFieldName;
		var _id = this.id;
		if (this.selectMultipleFiles) {
			nm += this.fileCount;
			_id += this.fileCount;
			this.fileCount++;
		}
		this.log("NAME:", nm, this.htmlFieldName, this.fileCount);
		this._fileInput.setAttribute("id", this.id);
		this._fileInput.setAttribute("name", nm);
		dojo.addClass(this._fileInput, "dijitFileInputReal");
		
		if(this.devMode){
			dojo.style(this._fileInput, "opacity", 1)
		}
		
		this._formNode.appendChild(this._fileInput);
		
	},
	
	_removeFileInput: function(){
		dojo.forEach(this.fileInputs, function(inp){
			inp.parentNode.removeChild(inp);
		});
		this.fileInputs = [];
		this.fileCount = 0;
	},
	
	_buildForm: function(node){
		// summary:
		//		Build the form that holds the fileInput
		//		This form also holds the class that targets
		//		the input to change its size
		//
		if (this._formNode) return;
		
		if (dojo.isIE) {
			// just to reiterate, IE is a steaming pile of code. 
			this._formNode = document.createElement('<form enctype="multipart/form-data" method="post">');
			this._formNode.encoding = "multipart/form-data";
			
		}
		else {
			// this is how all other sane browsers do it
			this._formNode = document.createElement('form');
			this._formNode.setAttribute("enctype", "multipart/form-data");
		}
		this._formNode.id = dijit.getUniqueId("form");
		if (node && dojo.style(node, "display").indexOf("inline") > -1) {
			document.body.appendChild(this._formNode);
		}
		else {
			node.appendChild(this._formNode);
		}
		this._setHtmlPostData();
		this._setFormStyle();
	},
	_setHtmlPostData: function(){
		if(this.postData){
			for (var nm in this.postData) {
				var f = document.createElement('input');
				dojo.attr(f, "type", "hidden");
				dojo.attr(f, "name", nm);
				dojo.attr(f, "value", this.postData[nm]);
				this._formNode.appendChild(f);
			}
		}
	},
	
	
	_setFormStyle: function(){
		// summary:
		//		Apply a dynamic style to the form and input
		//	description:
		// 		YAY! IE makes us jump through more hoops!
		//		We want to make the fileInput's button large enough to cover our
		//		fake button, and we do this with fontSize=(x)em.
		// 		It seems that after you build a fileInput, it's too late to style it. IE 
		//		styles the input field, but not the button. 
		//		To style the button, we'll create a class that fits, apply it to the form, 
		//		then it will cascade down properly. Geez.
		//
		// 		If the fake button is bigger than the fileInput, we need to resize
		//		the fileInput. Due to browser security, the only consistent sizing 
		//		method is font EMs. We're using a rough formula here to determine 
		//		if the fake button is very tall or very wide, and resizing based
		//		on the result.
		// 		We want a minimum of 2em, because on a Mac, system buttons have 
		//		rounded corners. The larger size moves that corner out of position
		var fake = this.getFakeButtonSize();
		var size = Math.max(2, Math.max(Math.ceil(fake.w / 60), Math.ceil(fake.h / 15)));
		
		// Now create a style associated with the form ID
		dojox.html.insertCssRule("#" + this._formNode.id + " input", "font-size:" + size + "em");
	},
	

	getFakeButtonSize: function(){
			// summary:
			//		Get the size and position of the Dijit Button or DOM node.
			//	description:
			//		This isn't easy. An awful lot has been accounted for, but a page full
			//		of cascading styles can be simply impossible to predict.
			// 		In these cases, it's reccomended that this function be 
			//		overwritten with more precise paramters
			//
			var fakeNode = (this.button.domNode) ? dojo.byId(this.button.id).parentNode : dojo.byId(this.button.id) || this.button;
			//this.log(this.id, "fakeNode", fakeNode)
			
			// This should be tested - or allow an ability to overwrite the settings
			if (fakeNode.tagName.toLowerCase() == "span") {
				fakeNode = dojo.byId(this.button.id)
			}
			// can't memoize this, because we need the location. And the size could possibly change anyway.
			var fake = dojo.coords(fakeNode, true);
			// if block, get the width from the style
			fake.w = (dojo.style(fakeNode, "display") == "block") ? dojo.style(fakeNode, "width") : fake.w;
			//relative and absolute positioning are totally different
			var p = fakeNode.parentNode.parentNode;
			if (p && dojo.style(p, "position") == "relative") {
				fake.x = dojo.style(p, "left");
				fake.y = dojo.style(p, "top");
			}
			if (p && dojo.style(p, "position") == "absolute") {
				fake.x = 0;
				fake.y = 0;
			}
			
			//Tweaking the size of the fileInput to be just a little bigger
			var s = 3;
			fake.x -= s;
			fake.y -= s;
			fake.w += s * 2;
			fake.h += s * 2;
			return fake;
		}
		
});

}

if(!dojo._hasResource["dojox.widget.FileInput"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.widget.FileInput"] = true;
dojo.provide("dojox.widget.FileInput");
dojo.experimental("dojox.widget.FileInput"); 


 

dojo.declare("dojox.widget.FileInput",
	dijit.form._FormWidget,
	{
	// summary: A styled input type="file"
	//
	// description: A input type="file" form widget, with a button for uploading to be styled via css,
	//	a cancel button to clear selection, and FormWidget mixin to provide standard dijit.form.Form
	//	support (FIXME: maybe not fully implemented) 

	// label: String
	//	the title text of the "Browse" button
	label: "Browse ...",

	// cancelText: String
	//	the title of the "Cancel" button
	cancelText: "Cancel",

	// name: String
	//	ugh, this should be pulled from this.domNode
	name: "uploadFile",

	templateString:"<div class=\"dijitFileInput\">\n\t<input id=\"${id}\" class=\"dijitFileInputReal\" type=\"file\" dojoAttachPoint=\"fileInput\" name=\"${name}\" />\n\t<div class=\"dijitFakeInput\">\n\t\t<input class=\"dijitFileInputVisible\" type=\"text\" dojoAttachPoint=\"focusNode, inputNode\" />\n\t\t<div class=\"dijitInline dijitFileInputText\" dojoAttachPoint=\"titleNode\">${label}</div>\n\t\t<div class=\"dijitInline dijitFileInputButton\" dojoAttachPoint=\"cancelNode\" \n\t\t\tdojoAttachEvent=\"onclick:_onClick\">${cancelText}</div>\n\t</div>\n</div>\n",
	
	startup: function(){
		// summary: listen for changes on our real file input
		this._listener = dojo.connect(this.fileInput,"onchange",this,"_matchValue");
		this._keyListener = dojo.connect(this.fileInput,"onkeyup",this,"_matchValue");
	},

	_matchValue: function(){
		// summary: set the content of the upper input based on the semi-hidden file input
		this.inputNode.value = this.fileInput.value;
		if(this.inputNode.value){
			this.cancelNode.style.visibility = "visible";
			dojo.fadeIn({ node: this.cancelNode, duration:275 }).play();
		}
	},

	setLabel: function(/* String */label,/* String? */cssClass){
		// summary: method to allow use to change button label
		this.titleNode.innerHTML = label;
	},

	_onClick: function(/* Event */e){
		// summary: on click of cancel button, since we can't clear the input because of
		// 	security reasons, we destroy it, and add a new one in it's place.
		dojo.disconnect(this._listener);
		dojo.disconnect(this._keyListener); 
		this.domNode.removeChild(this.fileInput);
		dojo.fadeOut({ node: this.cancelNode, duration:275 }).play(); 

		// should we use cloneNode()? can we?
		this.fileInput = document.createElement('input');
		this.fileInput.setAttribute("type","file");
		this.fileInput.setAttribute("id",this.id);
		this.fileInput.setAttribute("name",this.name);
		dojo.addClass(this.fileInput,"dijitFileInputReal");
		this.domNode.appendChild(this.fileInput);

		this._keyListener = dojo.connect(this.fileInput,"onkeyup",this,"_matchValue");
		this._listener = dojo.connect(this.fileInput,"onchange",this,"_matchValue"); 
		this.inputNode.value = ""; 
	}

});

}

if(!dojo._hasResource["dojox.widget.FileInputAuto"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.widget.FileInputAuto"] = true;
dojo.provide("dojox.widget.FileInputAuto");


 

dojo.declare("dojox.widget.FileInputAuto",
	dojox.widget.FileInput,
	{
	// summary: An extension on dojox.widget.FileInput providing background upload progress
	//
	// description: An extended version of FileInput - when the user focuses away from the input
	//	the selected file is posted via dojo.io.iframe to the url. example implementation
	//	comes with PHP solution for handling upload, and returning required data.
	//	
	// notes: the return data from the io.iframe is used to populate the input element with 
	//	data regarding the results. it will be a JSON object, like:
	//	
	//	results = { size: "1024", filename: "file.txt" }
	//	
	//	all the parameters allowed to dojox.widget.FileInput apply

	// url: String
	// 	the URL where our background FileUpload will be sent
	url: "",

	// blurDelay: Integer
	//	time in ms before an un-focused widget will wait before uploading the file to the url="" specified
	//	default: 2 seconds
	blurDelay: 2000,

	// duration: Integer
	//	The time in ms to use as the generic timing mechanism for the animations
	//	set to 1 or 0 for "immediate respose"
	duration: 500,

	// uploadMessage: String
	//	
	//	FIXME: i18n somehow?
	uploadMessage: "Uploading ...", 
	
	_sent: false,

	// small template changes, new attachpoint: overlay
	templateString:"<div class=\"dijitFileInput\">\n\t<input id=\"${id}\" name=\"${name}\" class=\"dijitFileInputReal\" type=\"file\" dojoAttachPoint=\"fileInput\" />\n\t<div class=\"dijitFakeInput\" dojoAttachPoint=\"fakeNodeHolder\">\n\t\t<input class=\"dijitFileInputVisible\" type=\"text\" dojoAttachPoint=\"focusNode, inputNode\" />\n\t\t<div class=\"dijitInline dijitFileInputText\" dojoAttachPoint=\"titleNode\">${label}</div>\n\t\t<div class=\"dijitInline dijitFileInputButton\" dojoAttachPoint=\"cancelNode\" dojoAttachEvent=\"onclick:_onClick\">${cancelText}</div>\n\t</div>\n\t<div class=\"dijitProgressOverlay\" dojoAttachPoint=\"overlay\">&nbsp;</div>\n</div>\n",

	startup: function(){
		// summary: add our extra blur listeners
		this._blurListener = dojo.connect(this.fileInput,"onblur",this,"_onBlur");
		this._focusListener = dojo.connect(this.fileInput,"onfocus",this,"_onFocus"); 
		this.inherited("startup",arguments);
	},

	_onFocus: function(){
		// summary: clear the upload timer
		if(this._blurTimer){ clearTimeout(this._blurTimer); }
	},

	_onBlur: function(){
		// summary: start the upload timer
		if(this._blurTimer){ clearTimeout(this._blurTimer); }
		if(!this._sent){
			this._blurTimer = setTimeout(dojo.hitch(this,"_sendFile"),this.blurDelay);		
		}
	},


	setMessage: function(/*String*/title){
		// summary: set the text of the progressbar
		
		// FIXME: this throws errors in IE?!?!?!? egads.		
		if(!dojo.isIE){ this.overlay.innerHTML = title;	}
	},
	
	_sendFile: function(/* Event */e){
		// summary: triggers the chain of events needed to upload a file in the background.
		if(!this.fileInput.value || this._sent){ return; }
		
		dojo.style(this.fakeNodeHolder,"display","none");
		dojo.style(this.overlay,"opacity","0");
		dojo.style(this.overlay,"display","block");

		this.setMessage(this.uploadMessage);

		dojo.fadeIn({ node: this.overlay, duration:this.duration }).play();

		var _newForm; 
		if(dojo.isIE){
			// just to reiterate, IE is a steaming pile of code. 
			_newForm = document.createElement('<form enctype="multipart/form-data" method="post">');
			_newForm.encoding = "multipart/form-data";
			
		}else{
			// this is how all other sane browsers do it
			_newForm = document.createElement('form');
			_newForm.setAttribute("enctype","multipart/form-data");
		}
		_newForm.appendChild(this.fileInput);
		dojo.body().appendChild(_newForm);
	
		dojo.io.iframe.send({
			url: this.url,
			form: _newForm,
			handleAs: "json",
			handle: dojo.hitch(this,"_handleSend")
		});
	},

	_handleSend: function(data,ioArgs){
		// summary: The callback to toggle the progressbar, and fire the user-defined callback
		if(!dojo.isIE){
			// otherwise, this throws errors in ie? FIXME:
			this.overlay.innerHTML = "";
		}
		
		this._sent = true;
		dojo.style(this.overlay,"opacity","0");
		dojo.style(this.overlay,"border","none");
		dojo.style(this.overlay,"background","none"); 

		this.overlay.style.backgroundImage = "none";
		this.fileInput.style.display = "none";
		this.fakeNodeHolder.style.display = "none";
		dojo.fadeIn({ node:this.overlay, duration:this.duration }).play(250);

		dojo.disconnect(this._blurListener);
		dojo.disconnect(this._focusListener);

		this.onComplete(data,ioArgs,this);
	},

	_onClick: function(e){
		// summary: accomodate our extra focusListeners
		if(this._blurTimer){ clearTimeout(this._blurTimer); }

		dojo.disconnect(this._blurListener);
		dojo.disconnect(this._focusListener);

		this.inherited("_onClick",arguments);

		this._blurListener = dojo.connect(this.fileInput,"onblur",this,"_onBlur");
		this._focusListener = dojo.connect(this.fileInput,"onfocus",this,"_onFocus"); 
	},

	onComplete: function(data,ioArgs,widgetRef){
		// summary: stub function fired when an upload has finished. 
		// data: the raw data found in the first [TEXTAREA] tag of the post url
		// ioArgs: the dojo.Deferred data being passed from the handle: callback
		// widgetRef: this widget pointer, so you can set this.overlay to a completed/error message easily
	}
});

dojo.declare("dojox.widget.FileInputBlind",
	dojox.widget.FileInputAuto,
	{
	// summary: An extended version of dojox.widget.FileInputAuto
	//	that does not display an input node, but rather only a button
	// 	and otherwise behaves just like FileInputAuto
	
	startup: function(){
		// summary: hide our fileInput input field
		this.inherited("startup",arguments);
		this._off = dojo.style(this.inputNode,"width");
		this.inputNode.style.display = "none";
		this._fixPosition();
	},
	
	_fixPosition: function(){		
		// summary: in this case, set the button under where the visible button is 
		if(dojo.isIE){
			dojo.style(this.fileInput,"width","1px");
		}else{
			dojo.style(this.fileInput,"left","-"+(this._off)+"px");
		}
	},

	_onClick: function(e){
		// summary: onclick, we need to reposition our newly created input type="file"
		this.inherited("_onClick",arguments);
		this._fixPosition(); 
	}
});

}

if(!dojo._hasResource["lucid.apps.FileBrowser"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["lucid.apps.FileBrowser"] = true;
dojo.provide("lucid.apps.FileBrowser");







lucid.addDojoCss("dojox/form/resources/FileInput.css");






dojo.declare("lucid.apps.FileBrowser", lucid.apps._App, {
	windows: [],
	init: function(args)
	{
		var cm = dojo.i18n.getLocalization("lucid", "common");
		var app = dojo.i18n.getLocalization("lucid", "apps");
		var places = dojo.i18n.getLocalization("lucid", "places");
		var sys = dojo.i18n.getLocalization("lucid", "system");
		this.win = new lucid.widget.Window({
			title: app["File Browser"],
			iconClass: this.iconClass,
			onClose: dojo.hitch(this, "kill")
		});
		this.fileArea = new lucid.widget.FileArea({path: (args.path || "file://"), region: "center"});
        this.updateTitle(this.fileArea.path);
        this.fileArea.refresh();
		this.pane = new dijit.layout.ContentPane({region: "left", splitter: true, minSize: 120, style: "width: 120px;"});
		var menu = new dijit.Menu({
			style: "width: 100%;"
		});
		dojo.forEach(lucid.config.filesystem.places, function(item){
			var item = new dijit.MenuItem({label: places[item.name] || item.name,
				iconClass: item.icon || "icon-16-places-folder",
				onClick: dojo.hitch(this.fileArea, "setPath", item.path)
			});
			menu.addChild(item);
		}, this);
		this.pane.setContent(menu.domNode);
		this.win.addChild(this.pane);
		this.win.addChild(this.fileArea);
		
		this.pathbar = new dijit.Toolbar({region: "center"});
		this.pathbox = new dijit.form.TextBox({
			style: "width: 90%;",
			value: args.path || "file://"
		});
		dojo.connect(this.fileArea, "onPathChange", this, function(){
			this.pathbox.setValue(this.fileArea.path);
			this.fixUploadPath(this.fileArea.path);
			this.statusbar.attr("label", "&nbsp;");
            this.updateTitle(this.fileArea.path);
		});
		this.pathbar.addChild(this.pathbox);
		this.goButton = new dijit.form.Button({
			label: cm.go,
			onClick: dojo.hitch(this, function(){
				this.fileArea.setPath(this.pathbox.getValue());
			})
		});
		this.pathbar.addChild(this.goButton);
		
		
		this.toolbar = new dijit.Toolbar({region: "top"});
			var button = new dijit.form.Button({
				onClick: dojo.hitch(this.fileArea, function(){
					this.setPath("file://");
				}),
				iconClass: "icon-16-places-user-home",
				label: places.Home
			});
			this.toolbar.addChild(button);
			var button = new dijit.form.Button({
				onClick: dojo.hitch(this.fileArea, this.fileArea.up),
				iconClass: "icon-16-actions-go-up",
				label: cm.up
			});
			this.toolbar.addChild(button);
			var button = new dijit.form.Button({
				onClick: dojo.hitch(this.fileArea, this.fileArea.refresh),
				iconClass: "icon-16-actions-view-refresh",
				label: cm.refresh
			});
			this.toolbar.addChild(button);
			this.quotabutton = new dijit.form.Button({
				onClick: dojo.hitch(this, "quotaNotice"),
				iconClass: "icon-16-devices-drive-harddisk",
				label: sys.quota
			});
			this.toolbar.addChild(this.quotabutton);
            this.makeUploadButton();
			var load = this.loadNode = document.createElement("div");
			dojo.addClass(load, "icon-loading-indicator");
			dojo.style(load, {
				display: "none",
				position: "absolute",
				top: "0px",
				right: "0px",
				margin: "7px"
			});
			this.toolbar.domNode.appendChild(load);
			
			dojo.connect(this.fileArea, "_loadStart", this, function(){
				dojo.style(load, "display", "block");
			});
			dojo.connect(this.fileArea, "_loadEnd", this, function(){
				dojo.style(load, "display", "none");
			});
		
		var bCont = new dijit.layout.BorderContainer({
			region: "top",
			gutters: false,
			style: "height: 42px;"	//This is really fucked up, since themes may use different heights for toolbars.
									//If BorderContainer ever supports more then one widget in one slot, please fix this.
		})
		bCont.addChild(this.toolbar);
		bCont.addChild(this.pathbar);
		this.win.addChild(bCont);
		// Status bar
		this.statusbar = new lucid.widget.StatusBar({region: "bottom"});
		this.win.addChild(this.statusbar);
		this.win.show();
		bCont.startup();
        this.win.resize();
		setTimeout(dojo.hitch(this, "makeUploader"), 1000);
	},
    updateTitle: function(path){
        var folders = path.split("/");
        var text = folders[folders.length-1] || folders[folders.length-2] || path;
        var app = dojo.i18n.getLocalization("lucid", "apps");
        this.win.attr("title", text + " - "+app["File Browser"]);
    },
	quotaNotice: function(){
		var cm = dojo.i18n.getLocalization("lucid", "common");
		var sys = dojo.i18n.getLocalization("lucid", "system");
		if(typeof(this.quotaWin) != "undefined"){ if(!this.quotaWin.closed){ return; } }
		lucid.filesystem.getQuota(this.fileArea.path, dojo.hitch(this, function(values){
			values.total = Math.round(values.total / 1024); values.remaining = Math.round(values.remaining / 1024); values.used = Math.round(values.used / 1024); 
			this.quotaWin = new lucid.widget.Window({
				title: sys.quota,
				resizable: false,
				height: "75px",
				width: "175px"
			});
			this.windows.push(this.quotaWin);
			var content = new dijit.layout.ContentPane({});
			var central = document.createElement("div");
			central.innerHTML = cm.total+": "+values.total+"kb<br>";
			central.innerHTML += cm.used+": "+values.used+"kb<br>";
			central.innerHTML += cm.remaining+": "+values.remaining+"kb";
            // TODO: get a progress bar in here?
			content.setContent(central);
			this.quotaWin.addChild(content);
			this.quotaWin.show();
			this.quotaWin.startup();
		}));
	},
	makeUploader: function(){
	    this.uploader = new dojox.form.FileUploader({
		    button: this.upbutton,
		    degradable: true,
			force: "html",
		    //uploadUrl: lucid.xhr("api.fs.io.upload")+"&path="+encodeURIComponent(this.fileArea.path),
            uploadUrl: lucid.xhr("api.fs.io.upload")+"?path="+encodeURIComponent(this.fileArea.path),
		    uploadOnChange: true,
            selectMultipleFiles: true
		});
		/*
        if(dojox.embed.Flash.available > 9){
            //fix button (workaround)
            this.fixButton();
            dojo.connect(this.uploader, "_connectInput", this, "fixButton");
        }*/
        this.doUploaderConnects();
	},
	
    fixButton: function(){
        var node = this.uploader.fileInputs[0];
        console.log(node);
        setTimeout(dojo.hitch(this, function(){
            var butNode = this.upbutton.domNode;
            var upNode = this.uploader._formNode;
            butNode.appendChild(upNode);
            dojo.style(butNode, "position", "relative");
            var right = node.offsetWidth-butNode.offsetWidth
            dojo.style(node, {
                top: "0px",
                left: "-"+right+"px",
                clip: "rect(0px, "+right-butNode.offsetWidth+"px, "+butNode.offsetHeight+"px, "+right+"px)"
            });
            dojo.style(node.parentNode, {position: "absolute", top: "0px", left: "0px"});
            dojo.query("span.dijitReset.dijitRight.dijitInline", this.upbutton.domNode).style("position", "relative");
        }), 500);
    },

    makeUploadButton: function(){
        if(this.upbutton)
            this.upbutton.destroy();
        var cm = dojo.i18n.getLocalization("lucid", "common");
        this.upbutton = new dijit.form.Button({
			iconClass: "icon-16-actions-mail-send-receive",
			label: cm.upload
		});
		this.toolbar.addChild(this.upbutton);
    },

	fixUploadPath: function(path){
	    var loc = window.location.href.split("/");
		loc.pop();
		loc = loc.join("/")+"/";
        //var newUrl = loc+lucid.xhr("api.fs.io.upload")+"&path="+encodeURIComponent(this.fileArea.path);
        var newUrl = loc+lucid.xhr("api.fs.io.upload")+"?path="+encodeURIComponent(this.fileArea.path);
		this.uploader.uploadUrl = newUrl;
		if(this.uploader.flashObject){
            this.uploader.destroy();
            this.makeUploadButton();
            this.makeUploader();
        }
	},
	
	doUploaderConnects: function(){
		var nls = dojo.i18n.getLocalization("lucid.widget", "filearea");
	    var uploader = this.uploader;
	    dojo.connect(uploader, "onChange", this, function(dataArray){
	       this.statusbar.attr({
	            label: nls.uploading.replace("%s", dataArray.length),
	            showProgress: true
	       });
	       this.statusbar.update({
	            indeterminate: true
	       });
	    });
	    dojo.connect(uploader, "onProgress", this, function(dataArray){
	        var progress = 0;
	        var total = 0;
	        dojo.forEach(dataArray, function(file){
	            progress += file.bytesLoaded;
	            total += file.bytesTotal;
	        });
	        this.statusbar.update({
	            indeterminate: false,
	            progress: progress,
	            maximum: total
	        });
            //workaround
            if(progress >= total) uploader.onComplete([{status: "success"}]);
	    });
	    uploader.onComplete = dojo.hitch(this, function(data){
	        if(data[data.length-1].status == "success"){
	           this.statusbar.attr({
	                label: nls.uploadingComplete,
	                showProgress: false
	           });
	           this.fileArea.refresh();
	        }else{
	           this.statusbar.attr({
	                label: "Error: "+data.details,
	                showProgress: false
	           });
	        }
	    });
        dojo.connect(uploader, "onError", this, function(data){
            this.statusbar.attr({
                label: "Error",
                showProgress: false
            });
        });
	},
	
	kill: function(){
		if(!this.win.closed){ this.win.close(); }
		dojo.forEach(this.windows, function(win){
			if(!win.closed) win.close();
		});
	}
})

}


dojo.i18n._preloadLocalizations("lucid.apps.nls.FileBrowser", ["ROOT","en","en-gb","en-us","es","es-es","fr","fr-fr","xx"]);
